package  
{
	import com.divillysausages.dsair.DSAir;
	import com.divillysausages.dsair.state.State;
	import com.divillysausages.dsair.state.FSM;
	import flash.display.Sprite;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	
	/**
	 * Test class for the StateManager and State classes
	 * @author Damian Connolly
	 */
	public class TestStateManager extends Sprite
	{
		private const STATE_INIT:String 	= "init";	// the name of the init state
		private const STATE_START:String	= "start";	// the name of the start state
		private const STATE_STOP:String		= "stop";	// the name of the stop state
		
		private var m_manager:FSM = null; // our state manager
		
		public function TestStateManager() 
		{
			// init the framework
			DSAir.init( this );
			
			// do our generic test
			//this._testBasic();
			
			// do our animated test
			this._testAnimated();
		}
		
		// tests with the generic state class
		private function _testBasic():void
		{			
			// create our state manager and add some states
			this.m_manager = new FSM;
			this.m_manager.addState( this.STATE_INIT, new State );
			this.m_manager.addState( this.STATE_START, new State );
			this.m_manager.addState( this.STATE_STOP, new State );
			
			// we're not in any state yet, so this will return null
			trace( "Our curr state: " + ( ( this.m_manager.currState != null ) ? this.m_manager.currState.name : "null" ) );
			trace( "Our next state: " + ( ( this.m_manager.nextState != null ) ? this.m_manager.nextState.name : "null" ) );
			
			// get a state
			trace( "The init state: " + this.m_manager.getState( this.STATE_INIT ) );
			trace( "Unknown state: " + this.m_manager.getState( "something" ) );
			
			// make sure the manager and name on the state is good
			trace( "Is the manager the same: " + ( this.m_manager.getState( this.STATE_INIT ).manager == this.m_manager ) );
			trace( "Is the name the same: " + ( this.m_manager.getState( this.STATE_INIT ).name == this.STATE_INIT ) );
			
			// change to a state
			var success:Boolean = this.m_manager.changeState( this.STATE_INIT );
			trace( "Did the change work: " + success );
			
			// trace our states
			trace( "Our curr state: " + ( ( this.m_manager.currState != null ) ? this.m_manager.currState.name : "null" ) );
			trace( "Our next state: " + ( ( this.m_manager.nextState != null ) ? this.m_manager.nextState.name : "null" ) );
			
			// try to change to the same state
			success = this.m_manager.changeState( this.STATE_INIT );
			trace( "Did the second change work: " + success );
		}
		
		// tests with animated states
		private function _testAnimated():void
		{
			// create our state manager and add some states
			this.m_manager = new FSM;
			this.m_manager.addState( this.STATE_INIT, new AnimState );
			this.m_manager.addState( this.STATE_START, new AnimState );
			this.m_manager.addState( this.STATE_STOP, new AnimState );
			
			// start the init state
			this.m_manager.changeState( this.STATE_INIT );
			
			// bind a key to move between states
			DSAir.bindKey( Keyboard.SPACE, this._changeStates );
			trace( "Press space to move between states" );
		}
		
		// change between the states
		private function _changeStates( e:KeyboardEvent ):void
		{
			if ( this.m_manager.currState.name == this.STATE_INIT )
				this.m_manager.changeState( this.STATE_START );
			else if ( this.m_manager.currState.name == this.STATE_START )
				this.m_manager.changeState( this.STATE_STOP, "hello world" ); // change with data
			else if ( this.m_manager.currState.name == this.STATE_STOP )
				this.m_manager.changeState( this.STATE_INIT );
		}
		
	}

}

import com.bit101.components.Label;
import com.bit101.components.Panel;
import com.divillysausages.dsair.DSAir;
import com.divillysausages.dsair.state.State;
import flash.events.Event;
import flash.utils.getTimer;

internal class AnimState extends State
{
	private var m_panel:Panel 	= null; // our panel bg
	private var m_label:Label 	= null;	// our label for our name
	private var m_dir:int		= 0;	// the direction that we're moving in
	
	override public function set name( s:String ):void 
	{
		super.name = s;
		this.m_label = new Label( this.m_panel, 10.0, 10.0, this.name );
	}
	
	public function AnimState()
	{
		// create our panel
		this.m_panel 	= new Panel( DSAir.stage );
		this.m_panel.x 	= -this.m_panel.width;
	}
	
	// called when we want this state to start - move in
	override public function start():void 
	{
		super.start();
		this.m_started 	= false; 	// we're animating in
		this.m_dir 		= 1;		// the dir to move in
		DSAir.stage.addEventListener( Event.ENTER_FRAME, this._onEnterFrame );
		
		// set the label
		this.m_label.text = this.name + " - starting";
	}
	
	// called when we want this state to stop - move out
	override public function stop():void 
	{
		super.stop();
		this.m_stopped 	= false;	// we're animating out
		this.m_dir		= -1;		// the dir to move in
		DSAir.stage.addEventListener( Event.ENTER_FRAME, this._onEnterFrame );
		
		// set the label
		this.m_label.text = this.name + " - stopping";
	}
	
	// called when this state has fully started
	override public function onStart( data:* = null ):void 
	{
		trace( "Anim state " + this.name + " has started! at " + getTimer() + ", data - " + data );
		
		// set the label
		this.m_label.text = this.name + " - started!";
	}
	
	// called when this state has fully stopped
	override public function onStop():void 
	{
		trace( "Anim state " + this.name + " has stopped! at " + getTimer() );
		
		// set the label
		this.m_label.text = this.name + " - stopped!";
	}
	
	// called when we're moving in or out
	private function _onEnterFrame( e:Event ):void
	{
		var dist:Number 	= 0.0; // how far we have to move
		var speed:Number 	= 0.2; // how fast to move it
		if ( this.m_dir == 1 )
		{
			dist 			= -this.m_panel.x * speed;
			this.m_panel.x += dist;
			if ( dist <= 1.0 )
			{
				// we're close enough, just finish
				this.m_panel.x 	= 0.0;
				this.m_started	= true;
				DSAir.stage.removeEventListener( Event.ENTER_FRAME, this._onEnterFrame );
			}
		}
		else
		{
			dist 			= -( this.m_panel.width + this.m_panel.x ) * speed;
			this.m_panel.x	+= dist;
			if ( dist >= -1.0 )
			{
				// we're close enough, just finish
				this.m_panel.x 	= -this.m_panel.width;
				this.m_stopped	= true;
				DSAir.stage.removeEventListener( Event.ENTER_FRAME, this._onEnterFrame );
			}
		}
	}
}